// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//==========================================================================
//  File:       CombinedHttpChannel.cs 
// 
//  Summary:    Merges the client and server HTTP channels
// 
//  Classes:    public HttpChannel
//
//=========================================================================
 
using System;
using System.Collections; 
using System.Runtime.Remoting; 
using System.Runtime.Remoting.Messaging;
using System.Globalization; 
using System.Security.Permissions;


namespace System.Runtime.Remoting.Channels.Http 
{
 
    public class HttpChannel : BaseChannelWithProperties, 
                               IChannelReceiver, IChannelSender, IChannelReceiverHook, ISecurableChannel
    { 
        // Cached key set value
        private static ICollection s_keySet = null;

        private HttpClientChannel  _clientChannel; // client channel 
        private HttpServerChannel  _serverChannel; // server channel
 
        private int    _channelPriority = 1;  // channel priority 
        private String _channelName = "http"; // channel name
        private bool _secure = false; 


        public HttpChannel()
        { 
            _clientChannel = new HttpClientChannel();
            _serverChannel = new HttpServerChannel(); 
        } // HttpChannel 

        public HttpChannel(int port) 
        {
            _clientChannel = new HttpClientChannel();
            _serverChannel = new HttpServerChannel(port);
        } // HttpChannel 

        public HttpChannel(IDictionary properties, 
                           IClientChannelSinkProvider clientSinkProvider, 
                           IServerChannelSinkProvider serverSinkProvider)
        { 
            Hashtable clientData = new Hashtable();
            Hashtable serverData = new Hashtable();

            // divide properties up for respective channels 
            if (properties != null)
            { 
                foreach (DictionaryEntry entry in properties) 
                {
                    switch ((String)entry.Key) 
                    {
                    // general channel properties
                    case "name": _channelName = (String)entry.Value; break;
                    case "priority": _channelPriority = Convert.ToInt32((String)entry.Value, CultureInfo.InvariantCulture); break; 
                    case "secure": _secure = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture);
                                    clientData["secure"] = entry.Value; 
                                    serverData["secure"] = entry.Value; 
                                    break;
                    default: 
                        clientData[entry.Key] = entry.Value;
                        serverData[entry.Key] = entry.Value;
                        break;
                    } 
                }
            } 
 
            _clientChannel = new HttpClientChannel(clientData, clientSinkProvider);
            _serverChannel = new HttpServerChannel(serverData, serverSinkProvider); 
        } // HttpChannel


        // 
        // ISecurableChannel implementation
        // 
        public bool IsSecured 
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get {
                if (_clientChannel != null)
                    return _clientChannel.IsSecured;
                if (_serverChannel != null) 
                    return _serverChannel.IsSecured;
                return false; 
            } 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            set { 
                if (((IList)ChannelServices.RegisteredChannels).Contains(this))
                    throw new InvalidOperationException(CoreChannel.GetResourceString("Remoting_InvalidOperation_IsSecuredCannotBeChangedOnRegisteredChannels"));
                if (_clientChannel != null)
                    _clientChannel.IsSecured = value; 
                if (_serverChannel != null)
                    _serverChannel.IsSecured = value; 
            } 
        }
 
        //
        // IChannel implementation
        //
 
        public int ChannelPriority
        { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _channelPriority; }
        } // ChannelPriority 

        public String ChannelName
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _channelName; }
        } // ChannelName 
 
        // returns channelURI and places object uri into out parameter
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public String Parse(String url, out String objectURI)
        {
            return HttpChannelHelper.ParseURL(url, out objectURI);
        } // Parse 

        // 
        // end of IChannel implementation 
        //
 

        //
        // IChannelSender implementation
        // 

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public IMessageSink CreateMessageSink(String url, Object remoteChannelData, 
                                                      out String objectURI)
        { 
            return _clientChannel.CreateMessageSink(url, remoteChannelData, out objectURI);
        } // CreateMessageSink

        // 
        // end of IChannelSender implementation
        // 
 

        // 
        // IChannelReceiver implementation
        //

        public Object ChannelData 
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _serverChannel.ChannelData; } 
        } // ChannelData
 

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
        public String[] GetUrlsForUri(String objectURI)
        { 
            return _serverChannel.GetUrlsForUri(objectURI);
        } // GetUrlsForUri 
 

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public void StartListening(Object data)
        {
            _serverChannel.StartListening(data);
        } // StartListening 

 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public void StopListening(Object data)
        { 
            _serverChannel.StopListening(data);
        } // StopListening

        // 
        // IChannelReceiver implementation
        // 
 
        //
        // IChannelReceiverHook implementation 
        //

        public String ChannelScheme {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return "http"; }
        } 
 
        public bool WantsToListen
        { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            get { return _serverChannel.WantsToListen; }

            set { _serverChannel.WantsToListen = value; } 
        } // WantsToListen
 
        public IServerChannelSink ChannelSinkChain 
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _serverChannel.ChannelSinkChain; }
        } // ChannelSinkChain

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public void AddHookChannelUri(String channelUri)
        { 
            _serverChannel.AddHookChannelUri(channelUri); 
        } // AddHookChannelUri
 
        //
        // IChannelReceiverHook implementation
        //
 

        // 
        // Support for properties (through BaseChannelWithProperties) 
        //
 
        public override IDictionary Properties
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            get 
            {
                ArrayList dictionaries = new ArrayList(2); 
                dictionaries.Add(_clientChannel.Properties); 
                dictionaries.Add(_serverChannel.Properties);
 
                // return a dictionary that spans all dictionaries provided
                return new AggregateDictionary(dictionaries);
            }
        } // Properties 

 
        public override Object this[Object key] 
        {
            get 
            {
                if (_clientChannel.Contains(key))
                    return _clientChannel[key];
                else 
                if (_serverChannel.Contains(key))
                    return _serverChannel[key]; 
 
                return null;
            } 

            set
            {
                if (_clientChannel.Contains(key)) 
                    _clientChannel[key] = value;
                else 
                if (_serverChannel.Contains(key)) 
                    _serverChannel[key] = value;
            } 
        } // this[]


        public override ICollection Keys 
        {
            get 
            { 
                if (s_keySet == null)
                { 
                    // Don't need to synchronize. Doesn't matter if the list gets
                    // generated twice.
                    ICollection clientKeys = _clientChannel.Keys;
                    ICollection serverKeys = _serverChannel.Keys; 

                    int count = clientKeys.Count + serverKeys.Count; 
                    ArrayList keys = new ArrayList(count); 

                    foreach (Object key in clientKeys) 
                    {
                        keys.Add(key);
                    }
 
                    foreach (Object key in serverKeys)
                    { 
                        keys.Add(key); 
                    }
 
                    s_keySet = keys;
                }

                return s_keySet; 
            }
        } // KeySet 
 

        // 
        // end of Support for properties
        //

    } // class HttpChannel 

 
 

    // an enumerator based off of a key set 
    // This is a duplicate of the class in mscorlib.
    internal class DictionaryEnumeratorByKeys : IDictionaryEnumerator
    {
        IDictionary _properties; 
        IEnumerator _keyEnum;
 
        public DictionaryEnumeratorByKeys(IDictionary properties) 
        {
            _properties = properties; 
            _keyEnum = properties.Keys.GetEnumerator();
        } // PropertyEnumeratorByKeys

        public bool MoveNext() { return _keyEnum.MoveNext(); } 
        public void Reset() { _keyEnum.Reset(); }
        public Object Current { get { return Entry; } } 
 
        public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
 
        public Object Key { get { return _keyEnum.Current; } }
        public Object Value { get { return _properties[Key]; } }

    } // DictionaryEnumeratorByKeys 

 
    // combines multiple dictionaries into one 
    //   (used for channel sink properties
    // This is a duplicate of the class in mscorlib. 
    internal class AggregateDictionary : IDictionary
    {
        private ICollection _dictionaries;
 
        public AggregateDictionary(ICollection dictionaries)
        { 
            _dictionaries = dictionaries; 
        } // AggregateDictionary
 
        //
        // IDictionary implementation
        //
 
        public virtual Object this[Object key]
        { 
            get 
            {
                foreach (IDictionary dict in _dictionaries) 
                {
                    if (dict.Contains(key))
                        return dict[key];
                } 

                return null; 
            } 

            set 
            {
                foreach (IDictionary dict in _dictionaries)
                {
                    if (dict.Contains(key)) 
                        dict[key] = value;
                } 
            } 
        } // Object this[Object key]
 
        public virtual ICollection Keys
        {
            get
            { 
                ArrayList keys = new ArrayList();
                // add keys from every dictionary 
                foreach (IDictionary dict in _dictionaries) 
                {
                    ICollection dictKeys = dict.Keys; 
                    if (dictKeys != null)
                    {
                        foreach (Object key in dictKeys)
                        { 
                            keys.Add(key);
                        } 
                    } 
                }
 
                return keys;
            }
        } // Keys
 
        public virtual ICollection Values
        { 
            get 
            {
                ArrayList values = new ArrayList(); 
                // add values from every dictionary
                foreach (IDictionary dict in _dictionaries)
                {
                    ICollection dictValues = dict.Values; 
                    if (dictValues != null)
                    { 
                        foreach (Object value in dictValues) 
                        {
                            values.Add(value); 
                        }
                    }
                }
 
                return values;
            } 
        } // Values 

        public virtual bool Contains(Object key) 
        {
            foreach (IDictionary dict in _dictionaries)
            {
                if (dict.Contains(key)) 
                    return true;
            } 
 
            return false;
        } // Contains 

        public virtual bool IsReadOnly { get { return false; } }
        public virtual bool IsFixedSize { get { return true; } }
 
        // The following three methods should never be implemented because
        // they don't apply to the way IDictionary is being used in this case 
        // (plus, IsFixedSize returns true.) 
        public virtual void Add(Object key, Object value) { throw new NotSupportedException(); }
        public virtual void Clear() { throw new NotSupportedException(); } 
        public virtual void Remove(Object key) { throw new NotSupportedException(); }

        public virtual IDictionaryEnumerator GetEnumerator()
        { 
            return new DictionaryEnumeratorByKeys(this);
        } // GetEnumerator 
 

        // 
        // end of IDictionary implementation
        //

        // 
        // ICollection implementation
        // 
 
        //ICollection
 
        public virtual void CopyTo(Array array, int index) { throw new NotSupportedException(); }

        public virtual int Count
        { 
            get
            { 
                int count = 0; 

                foreach (IDictionary dict in _dictionaries) 
                {
                    count += dict.Count;
                }
 
                return count;
            } 
        } // Count 

        public virtual Object SyncRoot { get { return this; } } 
        public virtual bool IsSynchronized { get { return false; } }

        //
        // end of ICollection implementation 
        //
 
        //IEnumerable 
        IEnumerator IEnumerable.GetEnumerator()
        { 
            return new DictionaryEnumeratorByKeys(this);
        }

    } // class AggregateDictionary 

 
} // namespace System.Runtime.Remoting.Channels.Http 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//==========================================================================
//  File:       CombinedHttpChannel.cs 
// 
//  Summary:    Merges the client and server HTTP channels
// 
//  Classes:    public HttpChannel
//
//=========================================================================
 
using System;
using System.Collections; 
using System.Runtime.Remoting; 
using System.Runtime.Remoting.Messaging;
using System.Globalization; 
using System.Security.Permissions;


namespace System.Runtime.Remoting.Channels.Http 
{
 
    public class HttpChannel : BaseChannelWithProperties, 
                               IChannelReceiver, IChannelSender, IChannelReceiverHook, ISecurableChannel
    { 
        // Cached key set value
        private static ICollection s_keySet = null;

        private HttpClientChannel  _clientChannel; // client channel 
        private HttpServerChannel  _serverChannel; // server channel
 
        private int    _channelPriority = 1;  // channel priority 
        private String _channelName = "http"; // channel name
        private bool _secure = false; 


        public HttpChannel()
        { 
            _clientChannel = new HttpClientChannel();
            _serverChannel = new HttpServerChannel(); 
        } // HttpChannel 

        public HttpChannel(int port) 
        {
            _clientChannel = new HttpClientChannel();
            _serverChannel = new HttpServerChannel(port);
        } // HttpChannel 

        public HttpChannel(IDictionary properties, 
                           IClientChannelSinkProvider clientSinkProvider, 
                           IServerChannelSinkProvider serverSinkProvider)
        { 
            Hashtable clientData = new Hashtable();
            Hashtable serverData = new Hashtable();

            // divide properties up for respective channels 
            if (properties != null)
            { 
                foreach (DictionaryEntry entry in properties) 
                {
                    switch ((String)entry.Key) 
                    {
                    // general channel properties
                    case "name": _channelName = (String)entry.Value; break;
                    case "priority": _channelPriority = Convert.ToInt32((String)entry.Value, CultureInfo.InvariantCulture); break; 
                    case "secure": _secure = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture);
                                    clientData["secure"] = entry.Value; 
                                    serverData["secure"] = entry.Value; 
                                    break;
                    default: 
                        clientData[entry.Key] = entry.Value;
                        serverData[entry.Key] = entry.Value;
                        break;
                    } 
                }
            } 
 
            _clientChannel = new HttpClientChannel(clientData, clientSinkProvider);
            _serverChannel = new HttpServerChannel(serverData, serverSinkProvider); 
        } // HttpChannel


        // 
        // ISecurableChannel implementation
        // 
        public bool IsSecured 
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get {
                if (_clientChannel != null)
                    return _clientChannel.IsSecured;
                if (_serverChannel != null) 
                    return _serverChannel.IsSecured;
                return false; 
            } 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            set { 
                if (((IList)ChannelServices.RegisteredChannels).Contains(this))
                    throw new InvalidOperationException(CoreChannel.GetResourceString("Remoting_InvalidOperation_IsSecuredCannotBeChangedOnRegisteredChannels"));
                if (_clientChannel != null)
                    _clientChannel.IsSecured = value; 
                if (_serverChannel != null)
                    _serverChannel.IsSecured = value; 
            } 
        }
 
        //
        // IChannel implementation
        //
 
        public int ChannelPriority
        { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _channelPriority; }
        } // ChannelPriority 

        public String ChannelName
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _channelName; }
        } // ChannelName 
 
        // returns channelURI and places object uri into out parameter
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public String Parse(String url, out String objectURI)
        {
            return HttpChannelHelper.ParseURL(url, out objectURI);
        } // Parse 

        // 
        // end of IChannel implementation 
        //
 

        //
        // IChannelSender implementation
        // 

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public IMessageSink CreateMessageSink(String url, Object remoteChannelData, 
                                                      out String objectURI)
        { 
            return _clientChannel.CreateMessageSink(url, remoteChannelData, out objectURI);
        } // CreateMessageSink

        // 
        // end of IChannelSender implementation
        // 
 

        // 
        // IChannelReceiver implementation
        //

        public Object ChannelData 
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _serverChannel.ChannelData; } 
        } // ChannelData
 

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
        public String[] GetUrlsForUri(String objectURI)
        { 
            return _serverChannel.GetUrlsForUri(objectURI);
        } // GetUrlsForUri 
 

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public void StartListening(Object data)
        {
            _serverChannel.StartListening(data);
        } // StartListening 

 
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public void StopListening(Object data)
        { 
            _serverChannel.StopListening(data);
        } // StopListening

        // 
        // IChannelReceiver implementation
        // 
 
        //
        // IChannelReceiverHook implementation 
        //

        public String ChannelScheme {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return "http"; }
        } 
 
        public bool WantsToListen
        { 
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            get { return _serverChannel.WantsToListen; }

            set { _serverChannel.WantsToListen = value; } 
        } // WantsToListen
 
        public IServerChannelSink ChannelSinkChain 
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
            get { return _serverChannel.ChannelSinkChain; }
        } // ChannelSinkChain

        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)] 
        public void AddHookChannelUri(String channelUri)
        { 
            _serverChannel.AddHookChannelUri(channelUri); 
        } // AddHookChannelUri
 
        //
        // IChannelReceiverHook implementation
        //
 

        // 
        // Support for properties (through BaseChannelWithProperties) 
        //
 
        public override IDictionary Properties
        {
            [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure, Infrastructure=true)]
            get 
            {
                ArrayList dictionaries = new ArrayList(2); 
                dictionaries.Add(_clientChannel.Properties); 
                dictionaries.Add(_serverChannel.Properties);
 
                // return a dictionary that spans all dictionaries provided
                return new AggregateDictionary(dictionaries);
            }
        } // Properties 

 
        public override Object this[Object key] 
        {
            get 
            {
                if (_clientChannel.Contains(key))
                    return _clientChannel[key];
                else 
                if (_serverChannel.Contains(key))
                    return _serverChannel[key]; 
 
                return null;
            } 

            set
            {
                if (_clientChannel.Contains(key)) 
                    _clientChannel[key] = value;
                else 
                if (_serverChannel.Contains(key)) 
                    _serverChannel[key] = value;
            } 
        } // this[]


        public override ICollection Keys 
        {
            get 
            { 
                if (s_keySet == null)
                { 
                    // Don't need to synchronize. Doesn't matter if the list gets
                    // generated twice.
                    ICollection clientKeys = _clientChannel.Keys;
                    ICollection serverKeys = _serverChannel.Keys; 

                    int count = clientKeys.Count + serverKeys.Count; 
                    ArrayList keys = new ArrayList(count); 

                    foreach (Object key in clientKeys) 
                    {
                        keys.Add(key);
                    }
 
                    foreach (Object key in serverKeys)
                    { 
                        keys.Add(key); 
                    }
 
                    s_keySet = keys;
                }

                return s_keySet; 
            }
        } // KeySet 
 

        // 
        // end of Support for properties
        //

    } // class HttpChannel 

 
 

    // an enumerator based off of a key set 
    // This is a duplicate of the class in mscorlib.
    internal class DictionaryEnumeratorByKeys : IDictionaryEnumerator
    {
        IDictionary _properties; 
        IEnumerator _keyEnum;
 
        public DictionaryEnumeratorByKeys(IDictionary properties) 
        {
            _properties = properties; 
            _keyEnum = properties.Keys.GetEnumerator();
        } // PropertyEnumeratorByKeys

        public bool MoveNext() { return _keyEnum.MoveNext(); } 
        public void Reset() { _keyEnum.Reset(); }
        public Object Current { get { return Entry; } } 
 
        public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
 
        public Object Key { get { return _keyEnum.Current; } }
        public Object Value { get { return _properties[Key]; } }

    } // DictionaryEnumeratorByKeys 

 
    // combines multiple dictionaries into one 
    //   (used for channel sink properties
    // This is a duplicate of the class in mscorlib. 
    internal class AggregateDictionary : IDictionary
    {
        private ICollection _dictionaries;
 
        public AggregateDictionary(ICollection dictionaries)
        { 
            _dictionaries = dictionaries; 
        } // AggregateDictionary
 
        //
        // IDictionary implementation
        //
 
        public virtual Object this[Object key]
        { 
            get 
            {
                foreach (IDictionary dict in _dictionaries) 
                {
                    if (dict.Contains(key))
                        return dict[key];
                } 

                return null; 
            } 

            set 
            {
                foreach (IDictionary dict in _dictionaries)
                {
                    if (dict.Contains(key)) 
                        dict[key] = value;
                } 
            } 
        } // Object this[Object key]
 
        public virtual ICollection Keys
        {
            get
            { 
                ArrayList keys = new ArrayList();
                // add keys from every dictionary 
                foreach (IDictionary dict in _dictionaries) 
                {
                    ICollection dictKeys = dict.Keys; 
                    if (dictKeys != null)
                    {
                        foreach (Object key in dictKeys)
                        { 
                            keys.Add(key);
                        } 
                    } 
                }
 
                return keys;
            }
        } // Keys
 
        public virtual ICollection Values
        { 
            get 
            {
                ArrayList values = new ArrayList(); 
                // add values from every dictionary
                foreach (IDictionary dict in _dictionaries)
                {
                    ICollection dictValues = dict.Values; 
                    if (dictValues != null)
                    { 
                        foreach (Object value in dictValues) 
                        {
                            values.Add(value); 
                        }
                    }
                }
 
                return values;
            } 
        } // Values 

        public virtual bool Contains(Object key) 
        {
            foreach (IDictionary dict in _dictionaries)
            {
                if (dict.Contains(key)) 
                    return true;
            } 
 
            return false;
        } // Contains 

        public virtual bool IsReadOnly { get { return false; } }
        public virtual bool IsFixedSize { get { return true; } }
 
        // The following three methods should never be implemented because
        // they don't apply to the way IDictionary is being used in this case 
        // (plus, IsFixedSize returns true.) 
        public virtual void Add(Object key, Object value) { throw new NotSupportedException(); }
        public virtual void Clear() { throw new NotSupportedException(); } 
        public virtual void Remove(Object key) { throw new NotSupportedException(); }

        public virtual IDictionaryEnumerator GetEnumerator()
        { 
            return new DictionaryEnumeratorByKeys(this);
        } // GetEnumerator 
 

        // 
        // end of IDictionary implementation
        //

        // 
        // ICollection implementation
        // 
 
        //ICollection
 
        public virtual void CopyTo(Array array, int index) { throw new NotSupportedException(); }

        public virtual int Count
        { 
            get
            { 
                int count = 0; 

                foreach (IDictionary dict in _dictionaries) 
                {
                    count += dict.Count;
                }
 
                return count;
            } 
        } // Count 

        public virtual Object SyncRoot { get { return this; } } 
        public virtual bool IsSynchronized { get { return false; } }

        //
        // end of ICollection implementation 
        //
 
        //IEnumerable 
        IEnumerator IEnumerable.GetEnumerator()
        { 
            return new DictionaryEnumeratorByKeys(this);
        }

    } // class AggregateDictionary 

 
} // namespace System.Runtime.Remoting.Channels.Http 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
